
Algorithm=function(){
  var self=this;

  self.taskStates=Array();

  self.addTasks=function(taskQueue){
    for(var i=0;i<taskQueue.length;i++)
      self.taskStates.push(new TaskState(taskQueue[i],i));
  }

  self.finished=function(){
    for(var i=0;i<self.taskStates.length;i++)
      if(self.taskStates[i].state!="finished")return false;
    self.taskStates=Array();
    return true;
  }
  //avança un tick de cada una i decideix que fer
  self.tick=function(){
    for(var i=0;i<self.taskStates.length;i++)
      self.taskStates[i].tick();
    //Log('after decide:');Log(self.taskStates);
    self.decide();
    //Log('before decide:');Log(self.taskStates);
  }
  //must be overriden
  self.decide=function(){
    Log('Decide not implemented :(');
  }
  self.getTaskStates=function(){
    return self.taskStates;
  }
}

Algorithms=function(){
  var self=this;

  self.algoList={};

  self.register=function(name,algorithm){
    self.algoList[name]=algorithm;
    self.algoNum++;
    return self;
  }
  self.unregister=function(name){
    delete self.algoList[name];
    return self;
  }
  self.get=function(name){
    return self.algoList[name];
  }
}


algorithms=new Algorithms();

algorithms.register("Select Algorithm", new function(){});

algorithms.register(
  "Ceiling Inmediate Priority",
  new function(){
    //inherits from algorithm
    this.__proto__=new Algorithm();
    var self=this;

    self.setTaskPrios=function(){
      var taskDeadlines=Array();

      for(var i=0;i<self.taskStates.length;i++){
        var task=self.taskStates[i];
        taskDeadlines.push([i,task.deadline]);
      }
      taskDeadlines.sort(function(a,b){return b[1]-a[1]});
      //Log(taskPeriods);
      for(var i=0;i<taskDeadlines.length;i++){
        //Log(taskPeriods[i]);
        //Log(self.taskStates[taskPeriods[i][0]]);
        self.taskStates[taskDeadlines[i][0]].setPrioBase(i);
      }
      return self;
    }

    //calculates the ceiling priority for each resource
    self.ceilingResources=function(){
      self.resources={};
      //Log("eeemmmmeeemmmsjm");
      //Log(self.taskStates);
      for(var i=0;i<self.taskStates.length;i++){
        var task=self.taskStates[i];
        //Log("jjjj");
        for(var j=0;j<task.actions.length;j++){
          var action=self.taskStates[i].actions[j];
          //Log("aaa");
          if(action[0] in self.resources){
            //Log("uuuu");
            self.resources[action[0]]=utils.max(Array(self.resources[action[0]],task.prioBase));
          }
          else{
            //Log("asdasj");
            self.resources[action[0]]=task.prioBase;
          }
        }
      }
      //Log('Resources:')
      //Log(self.resources);
      return self;
    }


    //this function decides what to do with tasks when tick
    //--overrides the method
    self.__proto__.decide=function(){
      self.setTaskPrios().ceilingResources();
      //Log('prios:');
      //for(var i=0;i<self.taskStates.length;i++)
      //  Log(self.taskStates[i].prioBase);
      //Log('resources:');
      //Log(self.resources);

      for(var i=0;i<self.taskStates.length;i++){
        var task=self.taskStates[i];
        if(task.quantum==0)
          task.nextAction();
        if(task.state!='finished' && task.state!='not inited')
          task.setPrioDyn(utils.max(Array(
                  task.prioBase,
                  self.resources[task.action[0]]
                  )));
        //last running task has a little more priority
        if(task.lastState=='running') task.prioDyn+=0.5;
      }
      var mostPrioTask=utils.max(self.taskStates,function(a,b){
        return a.prioDyn-b.prioDyn;
      });
      //Log('mostprioTask: '+mostPrioTask.id);
      //Log('prio: '+mostPrioTask.prioDyn);
      if(mostPrioTask.state=='finished' || mostPrioTask.state=='not inited')
        return self;
      mostPrioTask.changeState('running');
      //if(mostprioTask.lastState=='running') task.prioDyn-=0.5;
      //Log('mostprioTask: '+mostPrioTask.id);
      ////debugging
      //for(var i=0;i<self.taskStates.length;i++){
      //  var task=self.taskStates[i];
      //  Log('prioDyn('+task.id+'): '+task.prioDyn);
      //}
      //Log('-');
      //for(var i=0;i<self.taskStates.length;i++){
      //  var task=self.taskStates[i];
      //  Log('quantum('+task.id+'): '+task.quantum);
      //}
      //Log('-');
      //for(var i=0;i<self.taskStates.length;i++){
      //  var task=self.taskStates[i];
      //  Log('action('+task.id+'): '+task.action);
      //}
      for(var i=0;i<self.taskStates.length;i++){
        var task=self.taskStates[i];
        if(task.state=='running' && task.id!=mostPrioTask.id)
          task.changeState('blocked');
        if((task.state=='suspended' || task.state=='blocked') && task.prioBase>mostPrioTask.prioBase)
          task.RIP++;
      }
      //for(var i=0;i<self.taskStates.length;i++){
      //  var task=self.taskStates[i];
      //  if(task.state=='running'){
      //    Log("Running: "+task.id);
      //  }
      //}
      return self;
    }
  }
);
